﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BegEntities;
using BegInterfaces;
using System.Xml;
using System.IO;

namespace Database
{
    /// <summary>
    /// en klass för att hämta och spara data i en xml-fil, implementerar också interfacet IData
    /// </summary>
    public class XmlDatabase : IData
    {
        private string path = @"..\..\EmailDatabase.xml"; //sökvägen för xml-filen

        /// <summary>
        /// metod som tar ett email objekt som parameter och skriver ut det till xml-fil
        /// </summary>
        /// <param name="msg">ett email objekt</param>
        /// <returns>returnerar true eller false beroende på om skrivningen lyckades</returns>
        public bool AddMessage(Email msg)
        {
            if (File.Exists(path)) //om filen finns...
            {
                List<Email> allEmail = new List<Email>(); //skapar en lista
                allEmail.Add(msg); //lägger till objektet
                bool success = AddMessages(allEmail); //kallar på metoden AddMessages och med listan som parameter som svar returneras en bool

                return success;
            }
            else //om filen inte hittades
            {
                XmlWriterSettings settings = new XmlWriterSettings(); //inställningar för hur datan ska visas i xml-filen
                settings.Indent = true;
                settings.IndentChars = "   ";
                //
                XmlWriter writeXML = XmlWriter.Create(path, settings); //skapar ett xml-writer objekt med sökväg och inställningar

                try
                {   
                    writeXML.WriteStartDocument(); //lägger till en xml deklaration
                    writeXML.WriteStartElement("EmailList");
                    writeXML.WriteStartElement("Email");
                    writeXML.WriteAttributeString("ID", Convert.ToString(msg.ID));
                    writeXML.WriteElementString("Date", Convert.ToString(msg.Date));
                    writeXML.WriteElementString("From", msg.From.Name);
                    writeXML.WriteElementString("FromAddress", msg.From.Address);
                    writeXML.WriteElementString("IsRead", Convert.ToString(msg.IsRead));
                    writeXML.WriteElementString("Message", msg.Message);
                    writeXML.WriteElementString("MsgBox", Convert.ToString(msg.MsgBox));
                    writeXML.WriteElementString("Subject", msg.Subject);
                    writeXML.WriteElementString("To", msg.To.Name);
                    writeXML.WriteElementString("ToAddress", msg.To.Address);
                    writeXML.WriteEndElement();
                    writeXML.WriteEndElement();
                }
                catch(Exception)
                {
                    return false;
                }
                finally
                {
                    writeXML.Close(); // stänger ned strömmen
                }
                return true;
            }
        }

        /// <summary>
        /// metoden tar emot en lista med nya email objekt vilka läggs till en lista med
        /// objekt från xml-filen och som sen sedan skrivs till filen på nytt
        /// </summary>
        /// <param name="msgs">en lista med email objekt</param>
        /// <returns>true eller false beroende på om skrivningen lyckades eller inte</returns>
        public bool AddMessages(List<Email> msgs)
        {
            bool success;

            if (File.Exists(path)) //om filen finns
            {
                List<Email> allEmail = GetMessages(); //hämta alla email från fil

                foreach (Email email in msgs) //loopa igenom parameter listan
                {
                    allEmail.Add(email); //lägg varje email till listan med övriga email
                }

                success = AddXmlToFile(allEmail); //anropar metoden som skriver till xml-filen

                return success;
            }
            else //om listan inte finns, skriv till fil på en gång
            {
                success = AddXmlToFile(msgs);

                return success;
            }
        }

        /// <summary>
        /// tar bort ett email.
        /// </summary>
        /// <param name="msg">ett email objekt</param>
        /// <returns>true eller false beroende på om ändringen genomförts</returns>
        public bool DeleteMessage(Email msg)
        {
            List<Email> allEmail = GetMessages(); //hämtar alla email objekt

            foreach (Email e in allEmail)
            {
                if (e.ID == msg.ID) //loopar tills man hittar rätt objekt, jämför med ID
                {
                    allEmail.Remove(e); //tar bort objektet
                    break;
                }
            }
            bool success = AddXmlToFile(allEmail); //skriver listan med objekt till xml-fil

            return success;
        }

        /// <summary>
        /// hämtar alla email med begärd MessageBox 
        /// </summary>
        /// <param name="mbox">mbox kan vara Sent eller Inbox</param>
        /// <returns>returnerar en lista</returns>
        public List<Email> GetMessages(MessageBox mbox)
        {
            List<Email> allEmail = GetMessages(); //hämtar alla email
            List<Email> reqEmail = new List<Email>();

            foreach (Email e in allEmail)
            {
                if (e.MsgBox == mbox) //loopar igenom för att finna dem med rätt messagebox typ
                {
                    reqEmail.Add(e);
                }
            }
            return reqEmail;
        }

        /// <summary>
        /// hämtar alla email med ett xml-reader objekt
        /// </summary>
        /// <returns>en lista innehållande alla email objekt</returns>
        public List<Email> GetMessages()
        {
            List<Email> emailList = new List<Email>();

            XmlReaderSettings settings = new XmlReaderSettings(); //inställningar för hur xml-filen ska läsas
            settings.IgnoreWhitespace = true;
            settings.IgnoreComments = true;
            
            if (File.Exists(path))
            {
                try
                {
                    XmlReader emailReader = XmlReader.Create(path, settings); //skapar ett xml-reader objekt med sökväg och instälningar

                    try
                    {
                        if (emailReader.ReadToDescendant("Email")) //söker ett nästa element med namnet "Email"
                        {
                            do
                            {
                                Email email = new Email(); //skapar ett tomt email objekt
                                EmailAddress FromAddress = new EmailAddress();
                                EmailAddress ToAddress = new EmailAddress();
                                email.ID = System.Guid.Parse(emailReader["ID"]); //läser in id:et som är satt som ett attribut
                                emailReader.ReadStartElement("Email");
                                email.Date = DateTime.Parse(emailReader.ReadElementContentAsString()); //child element
                                FromAddress.Name = emailReader.ReadElementContentAsString();
                                FromAddress.Address = emailReader.ReadElementContentAsString();
                                email.From = FromAddress;
                                email.IsRead = Boolean.Parse(emailReader.ReadElementContentAsString());
                                email.Message = emailReader.ReadElementContentAsString();

                                string msgbox = emailReader.ReadElementContentAsString();
                                if (msgbox == "Inbox")
                                {
                                    email.MsgBox = BegEntities.MessageBox.Inbox;
                                }
                                else
                                {
                                    email.MsgBox = BegEntities.MessageBox.Sent;
                                }

                                email.Subject = emailReader.ReadElementContentAsString();
                                ToAddress.Name = emailReader.ReadElementContentAsString();
                                ToAddress.Address = emailReader.ReadElementContentAsString();
                                email.To = ToAddress;

                                emailList.Add(email);
                            }
                            //
                            while (emailReader.ReadToNextSibling("Email")); //letar efter nästa Email-element
                        }
                    }
                    catch (Exception)
                    {

                    }
                    finally
                    {
                        emailReader.Close(); //stänger ner xml-reader
                    }
                }
                catch(Exception)
                {

                }
            }
            return emailList;
        }

        /// <summary>
        /// ändrar värdet på isRead
        /// </summary>
        /// <param name="msg">ett Email objekt</param>
        /// <returns>bool</returns>
        public bool ModifyMessage(Email msg)
        {
            List<Email> allEmail = GetMessages();

            foreach (Email e in allEmail)
            {
                if (e.ID == msg.ID)
                {
                    e.IsRead = msg.IsRead;
                    break;
                }
            }
            bool success = AddXmlToFile(allEmail);
            return success;
        }

        /// <summary>
        /// skriver alla objekt i en lista till en xml-fil med xml-writer
        /// </summary>
        /// <param name="msgs">en lista innehållande email objekt</param>
        /// <returns>en bool beroende på om skrivningen lyckades eller inte</returns>
        public bool AddXmlToFile(List<Email> msgs)
        {
            //region innehåller kod som skapar en kopia av xml-filen, 
            //om ett fel uppstår under skrivningen har ursprungsfilen tagits bort men ej blivit ersatt
            #region
            string pathDir = @"..\..\Temp";
            string backupDB = pathDir + @"\EmailDatabase.xml";

            if (!Directory.Exists(pathDir))
            {
                Directory.CreateDirectory(pathDir);
            }

            if (File.Exists(path))
            {
                File.Copy(path, backupDB, true);
            }
            #endregion

            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "   ";

            try
            {
                XmlWriter writeXML = XmlWriter.Create(path, settings); //skapar ett xml-writer objekt med sökväg och inställningar

                try
                {
                    writeXML.WriteStartDocument();
                    writeXML.WriteStartElement("EmailList");
                    foreach (Email msg in msgs)
                    {
                        writeXML.WriteStartElement("Email");
                        writeXML.WriteAttributeString("ID", Convert.ToString(msg.ID));
                        writeXML.WriteElementString("Date", Convert.ToString(msg.Date));
                        writeXML.WriteElementString("From", msg.From.Name);
                        writeXML.WriteElementString("FromAddress", msg.From.Address);
                        writeXML.WriteElementString("IsRead", Convert.ToString(msg.IsRead));
                        writeXML.WriteElementString("Message", msg.Message);
                        writeXML.WriteElementString("MsgBox", Convert.ToString(msg.MsgBox));
                        writeXML.WriteElementString("Subject", msg.Subject);
                        writeXML.WriteElementString("To", msg.To.Name);
                        writeXML.WriteElementString("ToAddress", msg.To.Address);
                        writeXML.WriteEndElement();
                    }
                    writeXML.WriteEndElement();
                }
                catch (Exception)
                {
                    if (!File.Exists(path))
                    {
                        File.Copy(backupDB, path); //hämtar backupen om skrivningen misslyckades
                    }
                    return false;
                }
                finally
                {
                    writeXML.Close();
                }
            }
            catch(Exception)
            {
                return false;
            }
            return true;
        }
    }
}
